home *** CD-ROM | disk | FTP | other *** search
- #ifndef lint
- static char rcsid[] = "$Header: input.c,v 1.3 87/05/19 18:46:55 schoch Exp $";
- #endif
-
- #include "externs.h"
- #include <ctype.h>
- #include <strings.h>
- #include <sys/time.h>
-
- char instr [128];
- static int opponent;
-
- entermove (pstart, pend, color, pawntries)
- int *pstart, *pend, color, pawntries;
- {
- int i, readfds;
- int counter = 0;
- struct timeval timeout;
- char c;
- char *cp;
-
- timeout.tv_sec = (long int) 1;
- timeout.tv_usec = (long int) 0;
- wclear (win [OPPONENT]);
- while (TRUE) {
- drawok [color] = FALSE;
- if (color == ourcolor) {
- printf ("\007"); /* ring bell */
- if (drawok [1 - color]) {
- waddstr (win [MESSAGE], "draw offered");
- wclear (win [MESSAGE]);
- }
- wclear (win [INPUT]);
- waddstr (win [INPUT], ": ");
- waddstr (win [PROMPT], "your move");
- i = 0;
- while (TRUE) {
- move (win [INPUT]->_cury + win [INPUT]->_begy,
- win [INPUT]->_curx + win [INPUT]->_begx);
- refresh ();
- instr [i] = getchar ();
- if (instr [i] == '\n'
- || instr [i] == '\r')
- break;
- else if (instr [i] == '\f') { /* ^L */
- redraw();
- continue;
- } else if (instr [i] == '\b' /* ^H */
- || instr [i] == '\177') { /* delete */
- if (i > 0) {
- --i;
- wmove( win [INPUT],
- win [INPUT]->_cury,
- win [INPUT]->_curx - 1);
- wdelch (win [INPUT]);
- }
- continue;
- } else if (instr [i] == '\030' /* ^X */
- || instr [i] == '\025') { /* ^U */
- wclear (win [INPUT]);
- waddstr (win [INPUT], ": ");
- i = 0;
- continue;
- } else if (isupper (instr [i]))
- tolower (instr [i]);
- wclear (win [LEGAL]);
- if (isprint (instr [i]))
- waddch (win [INPUT], instr [i++]);
- }
- instr [i] = '\000';
- wclear (win [INPUT]);
- opponent = FALSE;
- } else {
- i = 0;
- wclear (win [MESSAGE]);
- waddstr (win [MESSAGE],
- "waiting for\nopponent's\nmove");
- refresh ();
- while (TRUE) {
- readfds = 1 + (1 << fileno(inp));
- while (select (fileno(inp)+1, &readfds, (int *)
- NULL, (int *) NULL,
- &timeout) < 0)
- if (errno != EINTR)
- error ("select in entermove");
- if (! (readfds & (1 << fileno(inp)))) {
- wclear (win [CLOCK]);
- if (counter++ % 2 == 1)
- waddch (win [CLOCK],'/');
- else
- waddch (win [CLOCK],'\\');
- move (win [CLOCK]->_begy,
- win [CLOCK]->_begx);
- refresh();
- if (readfds & 1) {
- c = getch();
- if (c == '\f' /* ^L */)
- redraw();
- }
- }
- else
- break;
- wclear (win [LEGAL]);
- }
- wclear (win [LEGAL]);
- if (fgets(instr, sizeof instr, inp) == NULL) {
- if (ferror(inp))
- error("read in entermove");
- dead = TRUE;
- if (state == PLAYING)
- state = OVER;
- } else {
- if (cp = index(instr, '\n'))
- *cp = '\0';
- if (cp = index(instr, '\r'))
- *cp = '\0';
- }
- opponent = TRUE;
- }
- wclear (win [PROMPT]);
- *pstart = *pend = 0;
- if (!strcmp (instr, "draw")) {
- drawok [color] = TRUE;
- if (!opponent)
- fputs("draw\r\n", out);
- break;
- } else if (!strcmp (instr, "resign")) {
- resign = TRUE;
- state = OVER;
- if (!opponent)
- fputs("resign\r\n", out);
- break;
- } else if (drawok [1 - color]) {
- if (!strcmp (instr, "yes")) {
- drawok [color] = TRUE;
- state = OVER;
- if (!opponent)
- fputs("yes\r\n", out);
- break;
- } else if (!strcmp (instr, "no")) {
- if (ourcolor != color)
- waddstr (win[MESSAGE], "draw refused");
- if (!opponent)
- fputs("no\r\n", out);
- break;
- } else {
- wclear (win [MESSAGE]);
- waddstr (win [MESSAGE],
- "draw offered\ntype yes or no\n");
- }
- } else if (!strcmp (instr, "o-o-o")
- && kingloc [color] % 10 == 5) {
- *pstart = kingloc [color];
- *pend = kingloc [color] - 2;
- if (!opponent)
- send_move(*pstart, *pend);
- break;
- } else if (!strcmp (instr, "o-o")
- && kingloc [color] % 10 == 5) {
- *pstart = kingloc [color];
- *pend = kingloc [color] + 2;
- if (!opponent)
- send_move(*pstart, *pend);
- break;
- } else if ((!strncmp (instr, "help", 4) || !strcmp (instr,""))
- && color == ourcolor) {
- wclear (win [MESSAGE]);
- waddstr (win [MESSAGE],
- "eg. qe4, p-k4\npxkb3, o-o-o\n");
- waddstr (win [MESSAGE],
- "draw, resign\nsay you'll lose");
- } else if (!strncmp (instr, "say", 3)) {
- if (opponent) {
- wclear (win [OPPONENT]);
- waddstr (win [OPPONENT], "message:\n");
- waddstr (win [OPPONENT], instr + 3);
- waddch (win [OPPONENT], '\n');
- } else
- fprintf(out, "say %s\r\n", instr+3);
- } else if ((!option [ANNOUNCEPAWNS])
- && (!strcmp (instr, "any")))
- if (pawntries)
- waddstr (win [PAWNTRIES], "pawntries\r");
- else
- waddstr (win [PAWNTRIES], "no pawntries\r");
- else {
- if ((i = parse_algebraic_move(pstart,pend,color))
- == NOWAY)
- i = parse_descriptive_move (pstart,pend,color);
- if (i == TRUE) {
- if (!opponent)
- send_move(*pstart, *pend);
- break;
- } else
- illegal (i, color);
- }
- }
- }
-
- #define boardpos(col, row) ((9 - (row)) * 10 + (col))
- #define RIGHT_SIDE 2
- #define RIGHT_FILE 1
-
- /* parse an algebraic move (e2-e4), and return TRUE for non error */
- /* opponent is true if this move is from the opponent. Moves set across
- * the network are standardized whether reverse is set or not. */
- parse_algebraic_move (pstart, pend, color)
- int *pstart, *pend, color;
- {
- int foundpiece = FALSE, i, j, piece, spot;
- LIST piecemoves (), lmember ();
-
- if (strlen (instr) == 5)
- if (instr [0] >= 'a' && instr [0] <= 'h'
- && instr [1] >= '1' && instr [1] <= '8'
- && instr [3] >= 'a' && instr [3] <= 'h'
- && instr [4] >= '1' && instr [4] <= '8') {
- *pstart = boardpos (instr[0]-'a'+1, instr[1]-'0');
- *pend = boardpos (instr[3]-'a'+1, instr[4]-'0');
- if (reverse && !opponent) {
- *pstart = 99 - *pstart;
- *pend = 99 - *pend;
- }
- return TRUE;
- } else
-
- return NOWAY;
- else if (strlen (instr) == 4)
- if (instr [0] >= 'a' && instr [0] <= 'h'
- && instr [1] >= '1' && instr [1] <= '8'
- && instr [2] >= 'a' && instr [2] <= 'h'
- && instr [3] >= '1' && instr [3] <= '8') {
- *pstart = boardpos (instr[0]-'a'+1, instr[1]-'0');
- *pend = boardpos (instr[2]-'a'+1, instr[3]-'0');
- if (reverse && !opponent) {
- *pstart = 99 - *pstart;
- *pend = 99 - *pend;
- }
- return TRUE;
- } else
-
- return NOWAY;
- else if (strlen (instr) == 2) {
- if (instr [0] < 'a' || instr [0] > 'h')
- return NOWAY;
- else if (instr [1] >= 'a' && instr [1] <= 'h') {
- /* pawn take */
- for (i = 2; i <= 7 ; i++) {
- spot = boardpos (instr[0]-'a'+1, i);
- if (reverse && !opponent)
- spot = 99 - spot;
- if (whose [spot] == color
- && occupant [spot] == PAWN)
- if (foundpiece)
- return AMBIGUOUS;
- else
- foundpiece = spot;
- }
- if (foundpiece) {
- *pstart = foundpiece;
- if (reverse && !opponent)
- *pend = boardpos ('i'-instr[1],
- 9 - foundpiece / 10)
- + pawndir [color];
- else
- *pend = boardpos (instr[1]-'a'+1,
- 9 - foundpiece / 10)
- + pawndir [color];
- return TRUE;
- } else
- return NOWAY;
- } else if (instr [1] >= '1' && instr [1] <= '8') {
- /* pawn move */
- *pend = boardpos (instr[0]-'a'+1, instr[1]-'0');
- if (reverse && !opponent)
- *pend = 99 - *pend;
- if (((ourcolor == BLACK) && (*pend <= 28))
- || ((ourcolor == WHITE) && (*pend >= 71)))
- return NOWAY;
- if ((whose [*pstart= *pend - pawndir [color]] == color
- && occupant [*pstart] == PAWN)
- || (whose [*pstart= *pstart - pawndir [color]] == color
- && occupant [*pstart] == PAWN))
- return TRUE;
- else
- return NOWAY;
- } else
- return NOWAY;
- } else if (strlen (instr) == 3) { /* eg. nc6 */
- if ((piece = piecetype(instr [0])) == ILLEGAL_PIECE)
- return NOWAY;
- if (instr [1] < 'a' || instr [1] > 'h'
- || instr [2] < '0' || instr [2] >'h')
- return NOWAY;
- *pend = boardpos (instr [1] - 'a' + 1, instr [2] - '0');
- if (reverse && !opponent)
- *pend = 99 - *pend;
- for (i = 1; i <= 8; i++) {
- for (j = 1; j <= 8; j++) {
- *pstart = boardpos (i, j);
- if (whose [*pstart] != color
- || occupant [*pstart] != piece
- || !lmember (*pend, piecemoves(*pstart,TRUE)))
- continue;
- if (foundpiece)
- return AMBIGUOUS;
- foundpiece = *pstart;
- }
- }
- if (*pstart = foundpiece)
- return TRUE;
- else
- return NOWAY;
- }
- return NOWAY; /* shoud never be reached */
- }
-
- /* parse a descriptive move (n-kb3), return TRUE for non error */
- parse_descriptive_move (pstart, pend, color)
- int *pstart, *pend, color;
- {
- char *sfrom, *sto, *alloca(), *index(), *afterslash;
- int nlegalbyfile = 0, nlegalbyside = 0, fromlegal = 0, frombyfile
- , frombyside, pawntake = FALSE, piece;
- LIST tryto, targets, piecemoves ();
- int i, j, spot, tobyfile, tobyside;
- struct {
- int row;
- int col;
- int goodness;
- } xfrom[100];
-
- /* sfrom is from string, sto is to string */
- sfrom = alloca (strlen (instr) + 1);
- strcpy(sfrom, instr);
- if ((sto = index (sfrom, '-')) == NULL)
- if ((sto = index (sfrom, 'x')) != NULL)
- pawntake = TRUE;
- else
- return NOWAY;
- *sto++ = '\0';
- if ((afterslash = index (sfrom, '/')) != NULL)
- *afterslash++ = '\0';
- if ((piece = piecetype(sfrom [strlen (sfrom) - 1])) == ILLEGAL_PIECE)
- return NOWAY;
- pawntake = pawntake && piece == PAWN;
- sfrom [strlen (sfrom) - 1] = '\0';
-
- /* build a list of legal from moves */
- for (i = 1; i <= 8; i++) {
- for (j = 1; j <= 8; j++) {
- spot = (9 - i) * 10 + j;
- if (whose [spot] != color)
- continue;
- if (occupant [spot] != piece)
- continue;
- xfrom [fromlegal].goodness = RIGHT_FILE;
- if (afterslash) {
- switch (xfrom [fromlegal].goodness
- = matchpos(afterslash, spot, color)) {
- case FALSE:
- continue;
- case ILLEGAL:
- return NOWAY;
- case RIGHT_SIDE:
- case RIGHT_FILE:
- break;
- }
- }
- if (*sfrom) {
- switch (xfrom [fromlegal].goodness
- = matchpos(sfrom, spot, color)) {
- case FALSE:
- continue;
- case ILLEGAL:
- return NOWAY;
- case RIGHT_SIDE:
- case RIGHT_FILE:
- break;
- }
- }
- xfrom[fromlegal].row = i;
- xfrom[fromlegal].col = j;
- fromlegal++;
- }
- }
-
- /* find all the consistent 'to' moves for those 'from' moves */
- for (i = 0; i < fromlegal; i++) {
- spot = (9 - xfrom [i].row) * 10 + xfrom [i].col;
- targets = piecemoves (spot, TRUE);
- for (tryto = targets; tryto != NULL; tryto = tryto->n) {
- switch (matchpos(sto, tryto->i, color)) {
- case RIGHT_FILE:
- if (xfrom [i].goodness == RIGHT_FILE) {
- if (piece == PAWN
- && pawntake == ((tryto->i % 10)
- == (xfrom[i].col)))
- continue;
- frombyfile = i;
- tobyfile = tryto -> i;
- nlegalbyfile++;
- }
- /* fall through */
- case RIGHT_SIDE:
- if (piece == PAWN
- && pawntake
- == ((tryto->i % 10) == (xfrom[i].col)))
- continue;
- frombyside = i;
- tobyside = tryto -> i;
- nlegalbyside++;
- break;
- case FALSE:
- continue;
- case ILLEGAL:
- return NOWAY;
- }
- }
- }
-
- /* complain if there are too many or if there are none */
- if (nlegalbyside != 1 && nlegalbyfile != 1) {
- if (nlegalbyside > 1)
- return AMBIGUOUS;
- else
- return NOWAY;
- }
-
- if (nlegalbyside == 1) {
- /* frombyside and tobyside now define the unique legal move */
- *pstart = (9 - xfrom[frombyside].row) * 10
- + xfrom[frombyside].col;
- *pend = tobyside;
- } else if (nlegalbyfile == 1) {
- /* frombyfile and tobyfile now define the unique legal move */
- *pstart = (9 - xfrom[frombyfile].row) * 10
- + xfrom[frombyfile].col;
- *pend = tobyfile;
- }
- return TRUE;
- }
-
- /* matchpos -- tells whether a square number matches the description
- desc is of the form b4 or qb4 or just b or 4 */
- static
- matchpos(desc, squareno, color)
- char *desc;
- int squareno, color;
- {
- static char *piececol = "rnbqkbnr";
- char side = FALSE, piece, rownum;
- int row, col;
-
- /* get row and col with player's king on (4,1) */
- /* (black's board is reflected) */
- row = 9 - squareno / 10;
- col = squareno % 10;
- if (color == BLACK)
- row = 9 - row;
-
- if (desc [0] == 'k' || desc [0] == 'q') {
- side = desc [0];
- if (!isdigit(desc[1]))
- desc++;
- }
- if (isalpha (desc [0])) {
- piece = desc [0];
- desc++;
- } else
- piece = side;
- if (rownum = isdigit (desc [0]))
- rownum = desc++ [0];
- if (( piece && index(piececol, piece) == NULL)
- || ( rownum && index("12345678", rownum) == NULL)
- || desc [0] != '\0')
- return ILLEGAL;
- else if ((side == 'k' && col <= 4) || (side == 'q' && col >= 5)
- || (rownum && row != rownum - '0')
- || (piece && piececol [col - 1] != piece))
- return FALSE;
- else if (side && !piece && piececol [col - 1] != side)
- return RIGHT_SIDE; /* eg. b/q-n2 when b is on queen side */
- else
- return RIGHT_FILE; /* eg. b/q-n2 when b is in queen file */
- }
-
- static piecetype(letter)
- char letter;
- {
- switch (letter) {
- case 'p':
- return PAWN;
- case 'r':
- return ROOK;
- case 'n':
- return KNIGHT;
- case 'b':
- return BISHOP;
- case 'q':
- return QUEEN;
- case 'k':
- return KING;
- default:
- return ILLEGAL_PIECE;
- }
- }
-
- /*
- * Send the move to the opponent */
- send_move(from, to)
- {
- fprintf(out, "%1c%1d-%1c%1d\r\n", from%10-1+'a', 9-from/10,
- to%10-1+'a', 9-to/10);
- }
-